<!-- 资源上传组件（走OSS） -->
<template>
    <div class="upload" :class="{'hidden-btn-type': !isShowBtn}">
        <el-upload
            ref="myUpload"
            :key="ossValue"
            :class="classInfo"
            action="/"
            :http-request="httpRequest"
            :multiple="ossMultiple && !isCropper"
            :limit="limit"
            :on-exceed="handleExceed"
            :on-remove="handleRemove"
            :on-success="handleSucess"
            :on-error="handleError"
            :on-change="handleChange"
            :before-upload="handleBeforeUpload"
            :before-remove="beforeRemove"
            :list-type="ossListType"
            :accept="ossAccept"
            :drag="ossDrag"
            :disabled="disabled"
            :file-list="fileList"
        >
            <el-button
                v-if="isShowBtn"
                class="oss-upload-button"
                v-html="ossBtnTile"
                type="primary"
                size="mini"
            ></el-button>
            <template v-if="ossOtherBtn && ossOtherBtn.length > 0">
                <a
                    v-for="(ali, aind) in ossOtherBtn"
                    slot="tip"
                    :key="aind"
                    :href="ali.url"
                    class="upload-btn-side"
                    :download="ali.name"
                >
                    {{ali.name}}
                </a>
            </template>
            <i v-if="ossDrag" class="el-icon-upload"></i>
            <div v-if="ossDrag" class="el-upload__text">
                将文件拖到此处，或
                <em>{{ossBtnTile}}</em>
            </div>
            <div v-if="ossListType !== 'picture'" class="el-upload__tip" v-html="ossInfo" slot="tip"></div>
        </el-upload>
        <p v-if="ossListType === 'picture'" v-html="ossInfo" class="oss-tip-info"></p>
        <el-dialog
            v-if="isCropper && (ossListType === 'picture' || ossListType === 'picture-card')"
            :width="`${cropperWidth >= 400 ? cropperWidth > 800 ? 800 : cropperWidth : 400}px`"
            center
            title=""
            :append-to-body="true"
            :visible.sync="isShowCropper"
            custom-class="cropper-dialog"
            :close-on-click-modal="false"
            :close-on-press-escape="false"
            :show-close="false"
        >
            <vue-cropper
                v-if="isShowCropper"
                :ratio="imgRatio"
                :max-width="cropperWidth"
                :origin-img-file="originImgFile"
                @closeCallback="closeCallback"
                @getNewImgCallback="getNewImgCallback"
            ></vue-cropper>
        </el-dialog>
    </div>
</template>
<script lang="ts">
import {
    Vue,
    Watch,
    Prop,
    Component
} from 'nuxt-property-decorator'
import vueCropper from './cpCropper.vue'
import {AliOssConf, ossConf} from '~/../config/ali.oss.conf'
import {serFileUrl} from '~/../config/server.url.conf'
const vmMd5 = require('md5')
const Oss = require('ali-oss')
@Component({
    name: 'uploadFile',
    components: {
        vueCropper
    }
})
export default class UploadFile extends Vue {
    @Prop()
    ossConfig?: AliOssConf
    @Prop()
    originalFileList: any
    @Prop()
    ossOtherBtn: any
    @Prop({
        type: String,
        default: ''
    })
    baseFileUrl!: string
    @Prop({
        type: String,
        default: '上传文件'
    })
    ossBtnTile!: string
    @Prop({
        type: String,
        default: 'text'
    })
    ossListType!: string
    @Prop({
        type: String,
        default: ''
    })
    ossValue!: string
    @Prop({
        type: String,
        default: ''
    })
    ossAccept!: string
    @Prop({
        type: String,
        default: ''
    })
    ossTarget!: string
    @Prop({
        type: String,
        default: ''
    })
    ossFormater!: string
    @Prop({
        type: String,
        default: ''
    })
    propName!: string
    @Prop({
        type: String,
        default: ''
    })
    ossInfo!: string
    @Prop({
        type: String,
        default: ''
    })
    ossClass!: string
    @Prop({
        type: Boolean,
        default: false
    })
    ossMultiple?: boolean
    @Prop({
        type: Boolean,
        default: false
    })
    ossDrag?: boolean
    @Prop({
        type: Boolean,
        default: false
    })
    disabled!: boolean
    @Prop({
        type: Boolean,
        default: false
    })
    isCropper!: boolean
    @Prop({
        type: Boolean,
        default: false
    })
    isModelType!: boolean
    @Prop({
        type: Number,
        default: 1
    })
    ossKey!: number
    @Prop({
        type: Number,
        default: 1
    })
    ossLimit!: number
    @Prop({
        type: Number,
        default: 0
    })
    ossFileSize!: number
    @Prop({
        type: Number,
        default: 0
    })
    imgRatio!: number
    @Prop({
        type: Number,
        default: 800
    })
    cropperWidth!: number
    timers: any = null
    client: any = null
    config: AliOssConf = ossConf
    serFileUrl: string = serFileUrl
    target: string = ''
    baseBucket: string = 'ciipResoruce' + (this.ossTarget ? '/' + this.ossTarget : '')
    fileList: [any?] = []
    newFileList: [any?] = []
    limit: number = 100
    classInfo: any = {
        'ct-oss-upload': true,
        'ct-oss-upload-sigle': false,
        [this.ossClass]: !!this.ossClass
    }
    isShowCropper: boolean = false
    originImgFile: any = {}
    allFileNum: number = 0
    @Watch('originalFileList', {immediate: false, deep: true})
    changeOriginalFileList () {
        if (this.originalFileList) {
            this.getOrigFileItem()
        }
    }
    @Watch('ossLimit', {immediate: false, deep: true})
    changeOssLimit (nv: number) {
        this.limit = nv === 1 ? 100 : nv
        this.classInfo['ct-oss-upload-sigle'] = nv === 1
    }
    get isShowBtn () {
        let flag = true
        flag = this.ossListType === 'picture-card' ? false : !this.ossDrag
        const num = this.allFileNum
        if (this.isModelType && num > 0) {
            flag = false
        }
        return flag
    }
    httpRequest (param: any) {
        if (this.isCropper) {
            this.originImgFile = param
            this.isShowCropper = true
        } else {
            this.ossUpload(param)
        }
    }
    handleError () {
        this.$message.error('文件上传失败')
    }
    handleSucess (response: any, file: any, fileList: any) {
        if (fileList.length > 1 && this.ossLimit === 1) {
            this.ossDelete(fileList[0], fileList, true)
            fileList.splice(0, 1)
        }
        this.parseAllNewsFileJson(fileList)
        if (response && file) {
            //
        }
    }
    handleRemove (file: any, fileList: any) {
        if (file.status === 'success') {
            this.parseAllNewsFileJson(fileList)
        }
    }
    handlePreview () {
        //
    }
    handleExceed (files: any, fileList: any) {
        this.$message.warning(`当前限制选择 ${this.ossLimit} 个文件，本次选择了 ${files.length} 个文件，共选择了 ${files.length + fileList.length} 个文件`)
    }
    beforeRemove (file: any, fileList: any) {
        if (file.status === 'success') {
            this.$confirm(`确定移除 ${file.name}？`, '提示', {
                closeOnClickModal: false,
                confirmButtonText: '确定',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                this.ossDelete(file, fileList)
            }).catch(() => {
                this.$message({
                    type: 'info',
                    message: '已取消删除'
                })
            })
            return false
        }
    }
    ossInitFn () {
        this.client = new Oss(this.config)
    }
    closeCallback (flag: boolean) {
        this.isShowCropper = false
        if (!flag) {
            const uploadFiles = (this.$refs.myUpload as any).uploadFiles
            const uid = this.originImgFile.file && this.originImgFile.file.uid
            uploadFiles.forEach((item: any, index: number) => {
                if (item.uid === uid) {
                    uploadFiles.splice(index, 1)
                }
            })
        }
    }
    getNewImgCallback (files: any) {
        this.closeCallback(true)
        this.ossUpload(files)
        const oArr = (this.$refs.myUpload as any).uploadFiles
        oArr.forEach((item: any, index: number):any => {
            if (item.uid === files.file.uid) {
                oArr[index].url = window.URL.createObjectURL(files.file)
            }
        })
    }
    handleChange () {
        //
    }
    handleBeforeUpload (file: any) {
        return this.vaditeFileSize(file) && this.vaditeFileFormater(file)
    }
    ossUpload (param: any) {
        if (!this.client) {
            param.onError('oss 未初始化完')
            return
        }
        const file = param.file
        const strName = file.name + file.lastModifiedDate + file.size + file.type
        const fileUuid = vmMd5(strName + (new Date()).getTime())
        const ossPath =
            this.baseBucket +
            '/' +
            (this.target ? this.target + '/' : '') +
            this.dataFormat(new Date()) +
            '/' +
            fileUuid +
            this.getFormat(file.name)
        this.client.multipartUpload(ossPath, file, {
            progress: (p: any) => {
                param.onProgress({percent: Math.floor(p * 100)})
            }
        }).then((result: any) => {
            if (result.res.status === 200) {
                param.onSuccess(result)
            } else {
                param.onError(result)
            }
        }).catch((err: any) => {
            param.onError(err)
        })
    }
    ossDelete (file: any, fileList: any, types?: any) {
        if (
            this.client &&
            file.response &&
            file.response.name
        ) {
            this.ossDeleteFn(
                file.uid,
                fileList,
                () => this.client.delete(file.response.name),
                types
            )
        } else if (file.fileUrl) {
            this.ossDeleteFn(
                file.uid,
                fileList,
                () => {
                    const promist = new Promise((resolve) => {
                        resolve('is ok')
                    })
                    return promist
                },
                types
            )
        } else {
            this.$message({
                type: 'error',
                message: '资源删除失败'
            })
        }
    }
    ossDeleteFn (uid: string | number, fileList: any, deleteFn: any, types: any) {
        deleteFn()
            .then(() => {
                if (!types) {
                    fileList.forEach((fli: any, findex: number) => {
                        if (uid === fli.uid) {
                            fileList.splice(findex, 1)
                            this.$emit('deleteFileCallback', fli)
                        }
                    })
                    this.$message({
                        type: 'success',
                        message: '资源删除成功'
                    })
                }
                this.parseAllNewsFileJson(fileList)
            })
            .catch(() => {
                if (!types) {
                    this.$message({
                        type: 'error',
                        message: '资源删除失败'
                    })
                }
            })
    }
    parseFileJson (file: any) {
        return {
            fileName: file.raw.name,
            fileSize: file.raw.size,
            fileFormat: this.getFormat(file.raw.name, true),
            fileUrl: file.response.name,
            fileShowUrl: file.response.name
        }
    }
    parseAllNewsFileJson (fileList: any) {
        this.newFileList = []
        if (fileList && fileList.length > 0) {
            fileList.forEach((item: any) => {
                if (item.response && item.response.name) {
                    this.newFileList.push(this.parseFileJson(item))
                }
            })
        }
        let datas: any = this.newFileList
        const dataLen = datas.length
        if (this.ossLimit === 1) {
            if (dataLen > 0) {
                datas = datas[0]
            } else {
                datas = ''
            }
        }
        this.allFileNum = fileList.length
        this.$emit('handleChangeFile', {
            data: datas,
            filevalue: this.ossValue,
            num: fileList.length,
            propName: this.propName ? this.propName : ''
        })
    }
    getOrigFileItem () {
        const orig = this.originalFileList
        if (orig.length > 0) {
            orig.forEach((item: any) => {
                const isItem = {...item}
                isItem.name = isItem.fileName
                isItem.fileUrl = isItem.fileUrl ? isItem.fileUrl : isItem.fileShowUrl
                isItem.url = this.serFileUrl + isItem.fileUrl
                this.fileList.push(isItem)
            })
            this.allFileNum = orig.length
        }
    }
    getFormat (name: string, md?: any) {
        let pos = name.lastIndexOf('.')
        let fom = ''
        if (md) {
            pos++
        }
        if (pos !== -1) {
            fom = name.substring(pos)
        }
        return fom
    }
    dataFormat (date: any) {
        const o = {
            y: date.getFullYear(),
            m: date.getMonth() + 1,
            d: date.getDate()
        }
        return o.y.toString() + (o.m >= 10 ? o.m : '0' + o.m).toString() + (o.d >= 10 ? o.d : '0' + o.d).toString()
    }
    vaditeFileFormater (file: any) {
        const name = file.name
        const fomt = this.getFormat(name)
        let arr: any = this.ossFormater
        let flag = true
        if (arr && fomt) {
            arr = arr.split(',')
            flag = false
            for (let ai = 0; ai < arr.length; ai++) {
                if (('.' + arr[ai]).toUpperCase() === fomt.toUpperCase()) {
                    flag = true
                    break
                }
            }
            if (!flag) {
                this.$message.warning(`当前文件上传不支持${fomt}格式`)
            }
        }
        return flag
    }
    vaditeFileSize (file: any) {
        const size = file.size / 1024 / 1024
        const vsize = this.ossFileSize
        let flag = true
        if (file.size === 0) {
            flag = false
            this.$message.warning('请上传大于0kb文件')
        } else if (vsize > 0 && size > vsize) {
            flag = false
            this.$message.warning(`当前限制文件大小为${vsize}MB，当前文件 ${file.name} 大小为 ${this.parseFileSize(file.size)}`)
        }
        return flag
    }
    parseFileSize (num: number) {
        let n = Number(num)
        const kb = 1024
        const mb = 1024 * 1024
        const gb = 1024 * 1024 * 1024
        const tb = 1024 * 1024 * 1024 * 1024
        let str = ''
        /* eslint-disable no-unused-expressions, no-sequences */
        switch (true) {
            case n < kb :
                str = 'B'
                break
            case n < mb && n >= kb :
                str = 'KB'
                n = n / kb
                break
            case n < gb && n >= mb :
                str = 'MB'
                n = n / mb
                break
            case n < tb && n >= gb :
                str = 'GB'
                n = n / gb
                break
            case n >= tb :
                str = 'TB'
                n = n / tb
                break
        }
        /* eslint-disable no-unused-expressions, no-sequences */
        return Math.round(n) + str
    }
    mounted () {
        this.limit = this.ossLimit === 1 ? 100 : this.ossLimit
        this.classInfo['ct-oss-upload-sigle'] = this.ossLimit === 1
        this.ossInitFn()
        this.getOrigFileItem()
    }
}
</script>
<style lang="scss">
    $ct_word_orang: #ff9900;
    $ct_height: 40px;
    $ct_border_radius: 4px;
    $ct_bule: #ccc;
    $ct_bule_hover: $blue;
    $ct_word_black: #333;
    $ct_border_gray: #eee;
    $white: #fff;
    $min-font-size: 12px;
    $mid-font-size: 16px;
    .oss-tip-info {
        line-height: $min-font-size;
        font-size: $min-font-size;
        color: #e53333;
    }

    .ct-oss-upload {
        display: inline-block;
        width: 100%;

        .el-upload__tip {
            color: #a9b0b4;
            font-size: $min-font-size;
            line-height: 18px;
        }
        .el-upload {
            .el-button {
                &.el-button--primary {
                    background-color: $ct_bule;
                    border-color: $ct_bule;
                    &:hover {
                        background-color: $ct_bule_hover;
                        border-color: $ct_bule_hover;
                    }
                }
            }
            &.el-upload--picture {
                float: left;
                .el-button {
                    width: 90px;
                    height: 90px;
                    background-color: transparent;
                    border: 1px dashed #ccc;
                    color: #ccc;
                    line-height: 20px;
                    span {
                        font-size: 20px;
                    }
                    p {
                        padding: 0;
                        margin: 0;
                        font-size: $mid-font-size;
                    }
                    &:hover {
                        background-color: transparent;
                        border: 1px dashed $ct_bule;
                        color: $ct_bule;
                    }
                }
            }
        }
        .upload-btn-side {
            color: $ct_bule;
            margin-left: 10px;
            position: relative;
            top: 10px;
            text-decoration: underline;

            &:hover {
                color: $ct_bule_hover;
            }
        }

        .el-upload-list {
            width: 100%;
            margin-top: 10px;

            .el-upload-list__item {
                float: left;
                margin-right: 20px;
                &:first-child{
                    margin-top: 5px;
                }
                .el-upload-list__item-name {
                    margin-right: 30px;
                    white-space: initial;

                    .el-icon-document {
                        display: inline-block;
                    }
                }
            }
            &.el-upload-list--picture {
                margin-top: 0;

                .el-upload-list__item:first-child {
                    margin-left: 20px;
                    margin-top: 0;
                }

                .el-upload-list__item {
                    border-radius: $ct_border_radius;
                    border-color: $ct_border_gray;
                    width: 90px;
                    height: 90px;
                    padding: 0;
                    margin-top: 0;
                    margin-bottom: 10px;

                    .el-upload-list__item-name,
                    .el-upload-list__item-status-label {
                        display: none;
                    }

                    .el-upload-list__item-thumbnail {
                        margin: 0;
                        width: auto;
                        height: auto;
                        @include imgCenter;
                    }

                    .el-icon-close {
                        width: 100%;
                        height: 100%;
                        top: 0;
                        left: 0;
                        visibility: hidden;
                        display: flex !important;
                        align-items: center;
                        justify-content: center;
                        background-color: rgba(0, 0, 0, 0.37);
                        color: $white;
                        font-size: $mid-font-size;
                        font-weight: bold;
                        text-align: center;
                        z-index: 2;
                    }

                    &:hover {
                        .el-icon-close {
                            visibility: visible;
                            color: #ccc;
                        }
                    }
                }
            }
        }
        .el-progress {
            position: absolute;
            top: auto;
            bottom: 0;
            line-height: 6px;
            .el-progress-bar {
                .el-progress-bar__outer {
                    height: 6px !important;
                }
            }
            .el-progress__text {
                display: none;
            }
        }
        .el-upload-list--picture .el-upload-list__item:hover .el-progress__text {
            display: none;
        }
        &.ct-oss-upload-sigle {
            .el-upload-list {
                .el-upload-list__item {
                    display: none !important;
                }
                .el-upload-list__item:first-child {
                    display: block !important;
                }
            }
        }
    }
    .el-dialog__wrapper{
        .el-dialog{
            &.cropper-dialog{
                padding: 0;
                .el-dialog__header{
                    display: none;
                }
                .el-dialog__body{
                    padding: 0 !important;
                }
            }
        }
    }
    .hidden-btn-type{
        .ct-oss-upload{
            .el-upload{
                display: none;
            }
        }
    }
</style>
